﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
using System.IO;
using TileEngine;
using System.Runtime.InteropServices;

namespace LevelEditor
{
    public partial class MapEditor : Form
    {
        public Game1 m_game;

        public MapEditor()
        {
            InitializeComponent();
        }

        private void exitToolStripMenuItem_Click(object sender, EventArgs e)
        {
            m_game.Exit();
            Application.Exit();
        }

        private void MapEditor_FormClosed(object sender, FormClosedEventArgs e)
        {
            m_game.Exit();
            Application.Exit();
        }

        private Bitmap TextureToBitmap(Texture2D a_texture)
        {
            MemoryStream ms = new MemoryStream();

            a_texture.SaveAsPng(ms, a_texture.Width, a_texture.Height);

            ms.Seek(0, SeekOrigin.Begin);
            Bitmap bmp = new Bitmap(Bitmap.FromStream(ms));

            ms.Close();

            return bmp;
        }
        
        private Bitmap TextureToBitmap(string a_filePath)
        {
            return new Bitmap(a_filePath);
        }

        private void LoadImageList(Bitmap a_tileSheet)
        {
            int tileIndex; 
            if (listTiles.Items.Count == 0)
            {
                tileIndex = 0;
            }
            else
            {
                tileIndex = listTiles.Items.Count - 1;
            }
            Console.WriteLine(tileIndex);

            for (int y = 0; y < a_tileSheet.Height / (TileMap.TileHeight); y++)
            {
                for (int x = 0; x < a_tileSheet.Width / (TileMap.TileWidth); x++)
                {
                    Bitmap newBitmap = a_tileSheet.Clone(
                        new System.Drawing.Rectangle(
                            x * (TileMap.TileWidth),
                            y * (TileMap.TileHeight),
                            TileMap.TileWidth,
                            TileMap.TileHeight),
                            System.Drawing.Imaging.PixelFormat.DontCare);
                    imageListTiles.Images.Add(newBitmap);                    
                    
                    string itemName = "";
                    switch (tileIndex)
                    {
                        case 0:
                            itemName = "Empty";
                            break;
                        case 1:
                            itemName = "White";
                            break;
                        case 2:
                            itemName = "Water_Shallow";
                            break;
                        case 3:
                            itemName = "Grass";
                            break;
                        case 4:
                            itemName = "Water_Deep";
                            break;
                        case 5:
                            itemName = "Ground1";
                            break;
                        case 6:
                            itemName = "Slope_Small";
                            break;
                        case 7:
                            itemName = "Black";
                            break;
                        case 8:
                            itemName = "Slope_Big";
                            break;
                        case 9:
                            itemName = "Ground2";
                            break;
                        case 10:
                            itemName = "Pink";
                            break;
                        default:
                            itemName = "";
                            break;
                    }
  
                    listTiles.Items.Add(new ListViewItem(itemName, tileIndex++));
                }
            }

            ListView_SetSpacing(listTiles, 48 + 35, 48 + 30);
        }

        //fixes the icon-spacing in the listView.
        ///////////////////////////////////////////////////////////
        [DllImport("user32.dll")]
        public static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);

        public int MakeLong(short lowPart, short highPart)
        {
            return (int)(((ushort)lowPart) | (uint)(highPart << 16));
        }

        public void ListView_SetSpacing(ListView listview, short cx, short cy)
        {
            const int LVM_FIRST = 0x1000;
            const int LVM_SETICONSPACING = LVM_FIRST + 53;
            // http://msdn.microsoft.com/en-us/library/bb761176(VS.85).aspx
            // minimum spacing = 4
            SendMessage(listview.Handle, LVM_SETICONSPACING,
            IntPtr.Zero, (IntPtr)MakeLong(cx, cy));

            // http://msdn.microsoft.com/en-us/library/bb775085(VS.85).aspx
            // DOESN'T WORK!
            // can't find ListView_SetIconSpacing in dll comctl32.dll
            //ListView_SetIconSpacing(listView.Handle, 5, 5);
        }
        ///////////////////////////////////////////////////////////

        private void MapEditor_Load(object sender, EventArgs e)
        {
            LoadImageList(TextureToBitmap(Application.StartupPath + @"\Content\textures\tilesheets\" + Game1.defaulttileSheetName + ".png"));            
            FixScrollBarScales();

            comboBoxTileType.Items.Clear();
            comboBoxTileType.Items.Add("None");
            comboBoxTileType.Items.Add("Start");            
            comboBoxTileType.Items.Add("Enemy");
            comboBoxTileType.Items.Add("Door");
            comboBoxTileType.Items.Add("EnemyBlocked");
            comboBoxTileType.Items.Add("Deadly");
            comboBoxTileType.Items.Add("Goal");

            comboBoxRotation.Items.Clear();
            comboBoxRotation.Items.Add("0°");
            comboBoxRotation.Items.Add("90°");
            comboBoxRotation.Items.Add("180°");
            comboBoxRotation.Items.Add("270°");

            comboBoxCurrentTileRotation.Items.Clear();
            comboBoxCurrentTileRotation.Items.Add("0°");
            comboBoxCurrentTileRotation.Items.Add("90°");
            comboBoxCurrentTileRotation.Items.Add("180°");
            comboBoxCurrentTileRotation.Items.Add("270°");

            comboBoxDrawingLayer.Items.Clear();
            comboBoxDrawingLayer.Items.Add("Background 1");
            comboBoxDrawingLayer.Items.Add("Background 2");
            comboBoxDrawingLayer.Items.Add("Interactive 1");
            comboBoxDrawingLayer.Items.Add("Interactive 2");
            comboBoxDrawingLayer.Items.Add("Foreground 1");
            comboBoxDrawingLayer.Items.Add("Foreground 2");
                      
            TileMap.EditorMode = true;
            TileMap.SelectTileMode = false;
            TileMap.tintColor = Microsoft.Xna.Framework.Color.White;
        }

        private void FixScrollBarScales()
        {
            Camera.ViewPortWidth = pctSurface.Width;
            Camera.ViewPortHeight = pctSurface.Height;

            Camera.Move(Vector2.Zero);

            vScrollBar1.Minimum = 0;
            vScrollBar1.Maximum = Camera.WorldRectangle.Height - Camera.ViewPortHeight;

            hScrollBar1.Minimum = 0;
            hScrollBar1.Maximum = Camera.WorldRectangle.Width - Camera.ViewPortWidth;
        }

        private void MapEditor_Resize(object sender, EventArgs e)
        {
            FixScrollBarScales();
        }
      
        private void listTiles_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (listTiles.SelectedIndices.Count > 0)
            {
                comboBoxRotation.SelectedIndex = 0;
                m_game.tileName = listTiles.SelectedItems[0].Text;
                m_game.DrawTile = listTiles.SelectedIndices[0];
            }
        }

        private void radioPassable_CheckedChanged(object sender, EventArgs e)
        {
            if (radioPassable.Checked)
            {
                m_game.SelectTileMode = false;
            }
            else
            {
                m_game.SelectTileMode = true;
            }
        }

        private void radioSelectionMode_CheckedChanged(object sender, EventArgs e)
        {
            if (radioSelectionMode.Checked)
            {
                m_game.SelectTileMode = true;
            }
            else
            {
                m_game.SelectTileMode = false;
            }
        }   

        private void timerGameUpdate_Tick(object sender, EventArgs e)
        {
            if (hScrollBar1.Maximum < 0 ||
                vScrollBar1.Maximum < 0)
            {
                FixScrollBarScales();
            }

            if (m_game.selectedTiles.Count > 0)
            {
                groupBoxTileProperties.Visible = true;
                
                bool allSameColor = false;
                bool allPassable = false;
                bool allSameName = false;
                foreach (MapSquare tile in m_game.selectedTiles)
                {
                    if (m_game.selectedTiles[0].m_attributes[1] == tile.m_attributes[1])
                    {
                        allSameName = true;
                    }
                    else
                    {
                        allSameName = false;
                        break;
                    }

                    if (!m_game.selectedTiles[0].m_blocked)
                    {
                        allPassable = true;
                    }
                    else
                    {
                        allPassable = false;
                        break;
                    }

                    if (m_game.selectedTiles[0].m_layerData[m_game.DrawLayer].Color == tile.m_layerData[m_game.DrawLayer].Color)
                    {
                        allSameColor = true;
                    }
                    else
                    {
                        allSameColor = false;
                        break;
                    }
                }

                if (allSameColor)
	            {
                    pictureBoxTileColor.BackColor = System.Drawing.Color.FromArgb(
                        m_game.selectedTiles[0].m_layerData[m_game.DrawLayer].Color.A,
                        m_game.selectedTiles[0].m_layerData[m_game.DrawLayer].Color.R,
                        m_game.selectedTiles[0].m_layerData[m_game.DrawLayer].Color.G,
                        m_game.selectedTiles[0].m_layerData[m_game.DrawLayer].Color.B);
	            }
                else
                {
                    pictureBoxTileColor.BackColor = System.Drawing.Color.White;                        
                }

                if (!allPassable)                
                    checkBoxBlocked.Checked = true;
                else
                    checkBoxBlocked.Checked = false;

                if (allSameName)
                    lblCurrentTileName.Text = m_game.selectedTiles[0].m_attributes[1];
                else
                    lblCurrentTileName.Text = "---";
            }
            else
            {
                groupBoxTileProperties.Visible = false;
            }

            m_game.Tick();           
        }

        private void loadMapToolStripMenuItem_Click(object sender, EventArgs e)
        {
            m_game.canDraw = false;
            openFileDialogLoadMap.ShowDialog();          
        }

        private void saveMapToolStripMenuItem_Click(object sender, EventArgs e)
        {
            m_game.canDraw = false;
            saveFileDialogSaveMap.ShowDialog();
        }

        private void clearMapToolStripMenuItem_Click(object sender, EventArgs e)
        {
            TileMap.ClearMap();
        }

        private void toolStripMenuItemImportTileSheet_Click(object sender, EventArgs e)
        {
            m_game.canDraw = false;
            openFileDialog1.ShowDialog();
        }

        private void openFileDialog1_FileOk(object sender, CancelEventArgs e)
        {            
            TileMap.LoadTileSheet(new FileStream(
                openFileDialog1.FileName,
                FileMode.Open), m_game.GraphicsDevice);

            LoadImageList(TextureToBitmap(TileMap.currentTileSheet));
        }

        private void openFileDialogLoadMap_FileOk(object sender, CancelEventArgs e)
        {
            try
            {
                TileMap.LoadMap(new FileStream(
                   openFileDialogLoadMap.FileName,
                    FileMode.Open));
            }
            catch
            {
                System.Diagnostics.Debug.Print("Unable to load map File!");
            }            
        }

        private void saveFileDialogSaveMap_FileOk(object sender, CancelEventArgs e)
        {
            Console.WriteLine(saveFileDialogSaveMap.FileName);

            TileMap.SaveMap(new FileStream(
                saveFileDialogSaveMap.FileName,
                FileMode.Create));
        }

        private void comboBoxDrawingLayer_SelectedIndexChanged(object sender, EventArgs e)
        {
            switch (comboBoxDrawingLayer.SelectedItem.ToString())
            {
                case "Background 1":
                    m_game.DrawLayer = 0;
                    break;
                case "Background 2":
                    m_game.DrawLayer = 1;
                    break;
                case "Interactive 1":
                    m_game.DrawLayer = 2;
                    break;
                case "Interactive 2":
                    m_game.DrawLayer = 3;
                    break;
                case "Foreground 1":
                    m_game.DrawLayer = 4;
                    break;
                case "Foreground 2":
                    m_game.DrawLayer = 5;
                    break;                    
            }
        }

        private void button1_Click(object sender, EventArgs e)
        {
            m_game.canDraw = false;
            if (colorDialog1.ShowDialog() == DialogResult.OK)
            {
                pictureBoxColor.BackColor = colorDialog1.Color;
                TileMap.tintColor.R = colorDialog1.Color.R;
                TileMap.tintColor.G = colorDialog1.Color.G;
                TileMap.tintColor.B = colorDialog1.Color.B;
                TileMap.tintColor.A = colorDialog1.Color.A;
            }
        }

        private void pictureBoxColor_Click(object sender, EventArgs e)
        {
            m_game.canDraw = false;
            if (colorDialog1.ShowDialog() == DialogResult.OK)
            {
                pictureBoxColor.BackColor = colorDialog1.Color;
                TileMap.tintColor.R = colorDialog1.Color.R;
                TileMap.tintColor.G = colorDialog1.Color.G;
                TileMap.tintColor.B = colorDialog1.Color.B;
                TileMap.tintColor.A = colorDialog1.Color.A;
            }
        }

        private void checkBoxBlocked_CheckedChanged(object sender, EventArgs e)
        {
            foreach (MapSquare tile in m_game.selectedTiles)
            {
                if (checkBoxBlocked.Checked)
                {
                    tile.m_blocked = true;
                }
                else
                {
                    tile.m_blocked = false;
                }
            }
        }

        private void pictureBoxTileColor_Click(object sender, EventArgs e)
        {
            m_game.canDraw = false;
            if (colorDialog1.ShowDialog() == DialogResult.OK)
            {
                foreach (MapSquare tile in m_game.selectedTiles)
                {
                    Microsoft.Xna.Framework.Color tmpColor = Microsoft.Xna.Framework.Color.White;
                    tmpColor.R = colorDialog1.Color.R;
                    tmpColor.G = colorDialog1.Color.G;
                    tmpColor.B = colorDialog1.Color.B;
                    tmpColor.A = colorDialog1.Color.A;

                    tile.m_layerData[m_game.DrawLayer].Color = tmpColor;
                }
                pictureBoxTileColor.BackColor = colorDialog1.Color;                
            }
        }

        private void comboBoxTileType_SelectedIndexChanged(object sender, EventArgs e)
        {
            foreach (MapSquare tile in m_game.selectedTiles)
            {
                switch (comboBoxTileType.SelectedItem.ToString())
                {
                    case "Start":
                        tile.m_attributes[0] = "START";
                        break;
                    case "Enemy":
                        tile.m_attributes[0] = "ENEMY";
                        break;
                    case "EnemyBlocked":
                        tile.m_attributes[0] = "BLOCK";
                        break;
                    case "Deadly":
                        tile.m_attributes[0] = "DEAD";
                        break;
                    case "Door":
                        tile.m_attributes[0] = "DOOR";
                        break;
                    case "Goal":
                        tile.m_attributes[0] = "GOAL";
                        break;
                    case "None":
                        tile.m_attributes[0] = "";
                        break;
                }
            }            
        }

        private void comboBoxDrawingLayer_DropDown(object sender, EventArgs e)
        {
            m_game.canDraw = false;
        }

        private void comboBoxDrawingLayer_DropDownClosed(object sender, EventArgs e)
        {
            m_game.canDraw = true;
        }

        private void vScrollBar1_Scroll(object sender, ScrollEventArgs e)
        {
            m_game.canDraw = false;
        }

        private void hScrollBar1_Scroll(object sender, ScrollEventArgs e)
        {
            m_game.canDraw = false;
        }

        private void comboBoxRotation_SelectedIndexChanged(object sender, EventArgs e)
        {
            switch (comboBoxRotation.SelectedItem.ToString())
            {
                case "0°":                    
                    TileMap.tileRotation = 0;
                    break;
                case "90°":
                    TileMap.tileRotation = 90;
                    break;
                case "180°":
                    TileMap.tileRotation = 180;
                    break;
                case "270°":
                    TileMap.tileRotation = 270;
                    break;
            }
        }

        private void comboBoxCurrentTileRotation_SelectedIndexChanged(object sender, EventArgs e)
        {
            foreach (MapSquare tile in m_game.selectedTiles)
            {
                switch (comboBoxCurrentTileRotation.SelectedItem.ToString())
                {
                    case "0°":
                        tile.m_layerData[m_game.DrawLayer].Rotation = 0;
                        break;
                    case "90°":
                        tile.m_layerData[m_game.DrawLayer].Rotation = 90;
                        break;
                    case "180°":
                        tile.m_layerData[m_game.DrawLayer].Rotation = 180;
                        break;
                    case "270°":
                        tile.m_layerData[m_game.DrawLayer].Rotation = 270;
                        break;
                }
            }
        }
    }
}
